﻿#include "VulkanLineWidget.h"
#include "Render/VulkanContext.h"
#include "Render/Widget/VulkanWindow.h"

CVulkanLineWidgets::~CVulkanLineWidgets()
{
    //销毁command buffer
    CVulkanContext::Get()->GetRecycleObjects()->CommandBuffers.Add(CommandBuffer);
}

void CVulkanLineWidgets::PreProcess(const TVector<SPreRenderLineWidget> &AllLineData)
{
    TVector<SPreRenderLineWidget> ValidData;
    for (const auto& LineData : AllLineData)
    {
        //检查数据是否合法
        if(LineData.Color.A==0)
        {
            continue;
        }

        if(LineData.Viewport.width<=0 || LineData.Viewport.height<=0)
        {
            continue;
        }

        //检查裁剪是否合法
        if(LineData.Scissor.extent.width<=0 || LineData.Scissor.extent.height<=0)
        {
            continue;
        }

        //如果裁剪矩形完全在视口外面，则不需要绘制
        if(LineData.Scissor.offset.x+LineData.Scissor.extent.width<=LineData.Viewport.x ||
            LineData.Scissor.offset.x>=LineData.Viewport.x+LineData.Viewport.width ||
            LineData.Scissor.offset.y+LineData.Scissor.extent.height<=LineData.Viewport.y ||
            LineData.Scissor.offset.y>=LineData.Viewport.y+LineData.Viewport.height)
        {
            continue;
        }


        ValidData.Add(LineData);
    }


    //创建渲染对象
    LineWidgets.Resize(ValidData.Num());
    for (int i = 0; i < ValidData.Num(); ++i)
    {
        LineWidgets[i].BindData(ValidData[i]);
    }

}

void CVulkanLineWidgets::CreateSelfRecordTasks(CVulkanWindow *InRenderSurface, SRenderCommandBuffers &OutCmdBuffersToExecute)
{
    if(LineWidgets.Num()==0)
    {
        return;
    }

    //创建command buffer
    if(!CommandBuffer)
    {
        //allocate a command buffer for this widget
        vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
            .setCommandPool(CVulkanContext::Get()->GetRenderThreadCommandPool())
            .setLevel(vk::CommandBufferLevel::eSecondary)
            .setCommandBufferCount(1);

        CommandBuffer = CVulkanContext::Get()->GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];
    }


    OutCmdBuffersToExecute.ImageWidgetRenderPassCommandBuffers.Add(CommandBuffer);

    vk::CommandBufferInheritanceInfo CommandBufferInheritanceInfo=vk::CommandBufferInheritanceInfo()
        .setRenderPass(CVulkanContext::Get()->GetWidgetRenderPass())
        .setFramebuffer(InRenderSurface->GetCurrentFrameBuffer())
        .setSubpass(0)
    ;

    vk::CommandBufferBeginInfo CommandBufferBeginInfo=vk::CommandBufferBeginInfo()
        .setFlags(vk::CommandBufferUsageFlagBits::eRenderPassContinue)
        .setPInheritanceInfo(&CommandBufferInheritanceInfo);

    CommandBuffer.begin(CommandBufferBeginInfo);

    CommandBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics,CVulkanContext::Get()->GetWidgetPipelines()->CanvasWidgetLinePipeline);
    for (auto& LineWidget : LineWidgets)
    {
        LineWidget.Draw(CommandBuffer);
    }

    CommandBuffer.end();



}

void CVulkanLineWidget::BindData(const SPreRenderLineWidget& Data)
{
    LineData=Data;
}

void CVulkanLineWidget::Draw(vk::CommandBuffer CommandBuffer)
{
    CommandBuffer.setViewport(0,1,&LineData.Viewport);
    CommandBuffer.setScissor(0,1,&LineData.Scissor);
                       
    SWidgetPipelines::SLineItemVertexPushConstant LineItemVertexPushConstant;
    LineItemVertexPushConstant.Color[0]=LineData.Color.R;
    LineItemVertexPushConstant.Color[1]=LineData.Color.G;
    LineItemVertexPushConstant.Color[2]=LineData.Color.B;
    LineItemVertexPushConstant.Color[3]=LineData.Color.A;

    LineItemVertexPushConstant.Start[0]=LineData.Start.X/ LineData.Viewport.width*2.0f-1.0f;
    LineItemVertexPushConstant.Start[1]=LineData.Start.Y/ LineData.Viewport.height*2.0f-1.0f;
    LineItemVertexPushConstant.End[0]=LineData.End.X/ LineData.Viewport.width*2.0f-1.0f;
    LineItemVertexPushConstant.End[1]=LineData.End.Y/ LineData.Viewport.height*2.0f-1.0f;
    LineItemVertexPushConstant.ZOrder=LineData.Depth;

               
    CommandBuffer.pushConstants(
        CVulkanContext::Get()->GetWidgetPipelines()->CanvasWidgetLinePipelineLayout
        ,vk::ShaderStageFlagBits::eVertex
        ,0
        ,sizeof(SWidgetPipelines::SLineItemVertexPushConstant)
        ,&LineItemVertexPushConstant);

    CommandBuffer.setLineWidth(LineData.Width);

    CommandBuffer.draw(2,1,0,0);
                    
}
